﻿using WorkItemAnalyser.Core.Assertions;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TypeMock.ArrangeActAssert;
using WorkItemAnalyser.Core;
using System.Linq;

namespace WorkItemAnalyser.Test
{
    [TestClass]
    public class ScenarioTests
    {
        [TestMethod]
        public void Scenario_ctor_CreatesEmptyFilterList()
        {
            //Arrange and Act
            var scenario = new Scenario("Bug", "Readify");

            //Assert
            Assert.AreEqual(0, scenario.FilterAssertions.Count());
        }

        [Isolated]
        [TestMethod]
        public void Scenario_AddFilter_AddsSingleItemToFilters()
        {
            //Arrange
            var filter = Isolate.Fake.Instance<IAssertion>();
            var scenario = new Scenario("Bug", "Readify");
            
            //Act
            scenario.AddFilter(filter);

            //Assert
            Assert.AreEqual(1, scenario.FilterAssertions.Count());
        }
        
        [Isolated]
        [TestMethod]
        public void Scenario_IsMatch_ReturnsTrueForCorrectProjectAndType()
        {
            //Arrange
            var workItem = Isolate.Fake.Instance<WorkItem>();
            Isolate.WhenCalled(() => workItem.Project.Name).WillReturn("Readify");
            Isolate.WhenCalled(() => workItem.Type.Name).WillReturn("Bug");

            var scenario = new Scenario("Bug", "Readify");

            //Act
            var result = scenario.IsMatch(workItem);

            //Assert
            Assert.IsTrue(result);
        }

        [Isolated]
        [TestMethod]
        public void Scenario_IsMatch_ReturnsFalseForIncorrectProject()
        {
            //Arrange
            var workItem = Isolate.Fake.Instance<WorkItem>();
            Isolate.WhenCalled(() => workItem.Project.Name).WillReturn("Readify");
            Isolate.WhenCalled(() => workItem.Type.Name).WillReturn("Bug");

            var scenario = new Scenario("Bug", "NotReadify");

            //Act
            var result = scenario.IsMatch(workItem);

            //Assert
            Assert.IsFalse(result);
        }

        [Isolated]
        [TestMethod]
        public void Scenario_IsMatch_ReturnsFalseForIncorrectType()
        {
            //Arrange
            var workItem = Isolate.Fake.Instance<WorkItem>();
            Isolate.WhenCalled(() => workItem.Project.Name).WillReturn("Readify");
            Isolate.WhenCalled(() => workItem.Type.Name).WillReturn("Bug");

            var scenario = new Scenario("NotBug", "Readify");

            //Act
            var result = scenario.IsMatch(workItem);

            //Assert
            Assert.IsFalse(result);
        }

        [Isolated]
        [TestMethod]
        public void Scenario_IsMatch_ReturnsFalseForIncorrectTypeAndProject()
        {
            //Arrange
            var workItem = Isolate.Fake.Instance<WorkItem>();
            Isolate.WhenCalled(() => workItem.Project.Name).WillReturn("Readify");
            Isolate.WhenCalled(() => workItem.Type.Name).WillReturn("Bug");

            var scenario = new Scenario("NotBug", "NotReadify");

            //Act
            var result = scenario.IsMatch(workItem);

            //Assert
            Assert.IsFalse(result);
        }

        [Isolated]
        [TestMethod]
        public void Scenario_IsMatch_ReturnsFalseForSingleFailingFilterAndCorrectBaseQuery()
        {
            //Arrange
            var workItem = Isolate.Fake.Instance<WorkItem>();
            Isolate.WhenCalled(() => workItem.Project.Name).WillReturn("Readify");
            Isolate.WhenCalled(() => workItem.Type.Name).WillReturn("Bug");

            var filter = Isolate.Fake.Instance<IAssertion>();
            Isolate.WhenCalled(() => filter.Execute(null)).WillReturn(new[] { new AssertionResult { IsValid = false } });

            var scenario = new Scenario("Bug", "Readify");
            scenario.AddFilter(filter);

            //Act
            var result = scenario.IsMatch(workItem);

            //Assert
            Assert.IsFalse(result);
        }

        [Isolated]
        [TestMethod]
        public void Scenario_IsMatch_ReturnsFalseForSinglePassingFilterAndIncorrectBaseQuery()
        {
            //Arrange
            var workItem = Isolate.Fake.Instance<WorkItem>();
            Isolate.WhenCalled(() => workItem.Project.Name).WillReturn("Readify");
            Isolate.WhenCalled(() => workItem.Type.Name).WillReturn("Bug");

            var filter = Isolate.Fake.Instance<IAssertion>();
            Isolate.WhenCalled(() => filter.Execute(null)).WillReturn(new[] { new AssertionResult { IsValid = true } });

            var scenario = new Scenario("Bug", "NotReadify");
            scenario.AddFilter(filter);

            //Act
            var result = scenario.IsMatch(workItem);

            //Assert
            Assert.IsFalse(result);
        }

        [Isolated]
        [TestMethod]
        public void Scenario_IsMatch_ReturnsFalseForMixedFilterResultsAndCorrectBaseQuery()
        {
            //Arrange
            var workItem = Isolate.Fake.Instance<WorkItem>();
            Isolate.WhenCalled(() => workItem.Project.Name).WillReturn("Readify");
            Isolate.WhenCalled(() => workItem.Type.Name).WillReturn("Bug");

            var filter = Isolate.Fake.Instance<IAssertion>();
            Isolate.WhenCalled(() => filter.Execute(null)).WillReturn(new[] 
                                                                                                        { new AssertionResult { IsValid = true },
                                                                                                            new AssertionResult {IsValid = false},
                                                                                                            new AssertionResult {IsValid = true}
                                                                                                        });

            var scenario = new Scenario("Bug", "Readify");
            scenario.AddFilter(filter);

            //Act
            var result = scenario.IsMatch(workItem);

            //Assert
            Assert.IsFalse(result);
        }

        [Isolated]
        [TestMethod]
        public void Scenario_IsMatch_ReturnsFalseForMixedFilterResultsAndIncorrectBaseQuery()
        {
            //Arrange
            var workItem = Isolate.Fake.Instance<WorkItem>();
            Isolate.WhenCalled(() => workItem.Project.Name).WillReturn("Readify");
            Isolate.WhenCalled(() => workItem.Type.Name).WillReturn("Bug");

            var filter = Isolate.Fake.Instance<IAssertion>();
            Isolate.WhenCalled(() => filter.Execute(null)).WillReturn(new[] 
                                                                                                        { new AssertionResult { IsValid = true },
                                                                                                            new AssertionResult {IsValid = false},
                                                                                                            new AssertionResult {IsValid = true}
                                                                                                        });

            var scenario = new Scenario("Bug", "NotReadify");
            scenario.AddFilter(filter);

            //Act
            var result = scenario.IsMatch(workItem);

            //Assert
            Assert.IsFalse(result);
        }

        [Isolated]
        [TestMethod]
        public void Scenario_IsMatch_ReturnsTrueForCorrectFilterResultsAndCorrectBaseQuery()
        {
            //Arrange
            var workItem = Isolate.Fake.Instance<WorkItem>();
            Isolate.WhenCalled(() => workItem.Project.Name).WillReturn("Readify");
            Isolate.WhenCalled(() => workItem.Type.Name).WillReturn("Bug");

            var filter = Isolate.Fake.Instance<IAssertion>();
            Isolate.WhenCalled(() => filter.Execute(null)).WillReturn(new[] 
                                                                                                        { new AssertionResult { IsValid = true },
                                                                                                            new AssertionResult {IsValid = true}
                                                                                                        });

            var scenario = new Scenario("Bug", "Readify");
            scenario.AddFilter(filter);

            //Act
            var result = scenario.IsMatch(workItem);

            //Assert
            Assert.IsTrue(result);
        }
    }
}